/*
	Pulsar engine. Core.
	Internal include file. Windows implementation for semaphores and critical sections

	Copyright (C) 2013-2014 Dmitry Dolgov

	This program is free software; you can redistribute it and/or modify it under the terms of the
	GNU General Public License as published by the Free Software Foundation; either version 2 of
	the License, or (at your option) any later version.

	This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
	without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
	See the GNU General Public License for more details.
*/


#if !defined(PL_WINDOWS) && !defined(PL_WINDOWS64)
#error "Wrong Operation System"
#endif

#ifndef _PL_SYNCHRONIZE_WIN_H_
#define _PL_SYNCHRONIZE_WIN_H_

namespace pl
{

class SemaphoreImpl
{
public:
	SemaphoreImpl(pl_uint32 iniCount, pl_uint32 maxCount, const pl_char* name = NULL) :
	_sema(CreateSemaphore(NULL, iniCount, maxCount, name))
	{
		PL_STATIC_ASSERT(sizeof(SemaphoreImpl) < RESERVED_SIZE);
		return;
	}

	~SemaphoreImpl()
	{
		CloseHandle(_sema);
		return;
	}

	void release()
	{
		ReleaseSemaphore(_sema, 1, NULL);
		return;
	}

	bool wait(pl_int32 timeMs)
	{
		if (timeMs == -1)
		{
			timeMs = INFINITE;
		}
		switch (WaitForSingleObject(_sema, timeMs))
		{
			case WAIT_OBJECT_0:
				return true;

			case WAIT_TIMEOUT:
				return false;
		}
		PL_ASSERTE(false, PL_T("WaitForSingleObject() failed"));
		return false;
	}

private:
	HANDLE _sema;
};

class CriticalSectionImpl
{
public:
	CriticalSectionImpl(const pl_char* name = NULL)
	{
		PL_STATIC_ASSERT(sizeof(CriticalSectionImpl) < RESERVED_SIZE);
		InitializeCriticalSection(&_cs);
		return;
	}

	~CriticalSectionImpl()
	{
		DeleteCriticalSection(&_cs);
		return;
	}

	void enter()
	{
		EnterCriticalSection(&_cs);
		return;
	}

	void leave()
	{
		LeaveCriticalSection(&_cs);
		return;
	}

	bool tryEnter()
	{
		return TryEnterCriticalSection(&_cs) ? true : false;
	}

private:
	CRITICAL_SECTION _cs;
};

} // namespace pl

#endif // _PL_SYNCHRONIZE_WIN_H_

//
// End of file 'pulsar_synchronize_win.h'
//
